Skip to content

Commit ee92a11

Browse files
committed
SILGen: Simplify on-demand function emission
This mechanism is used for imported functions with bodies synthesized by the ClangImporter, as well as on-demand accessors synthesized when required for a protocol conformance (eg, a _read accessor, or a _modify on a property whose opaque access pattern doesn't use a _modify, such as an @objc dynamic property). Previously this was intertwined with the 'delayed function' mechanism, which is similar, but used for a different case -- implicit functions inside the same translation unit. Untangle these to allow further simplifications.
1 parent 89a671d commit ee92a11

File tree

5 files changed

+56
-50
lines changed

5 files changed

+56
-50
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -578,18 +578,37 @@ static bool isEmittedOnDemand(SILModule &M, SILDeclRef constant) {
578578
return false;
579579

580580
auto *d = constant.getDecl();
581-
auto *dc = d->getDeclContext()->getModuleScopeContext();
581+
auto *dc = d->getDeclContext();
582582

583-
if (isa<ClangModuleUnit>(dc))
584-
return true;
583+
switch (constant.kind) {
584+
case SILDeclRef::Kind::Func: {
585+
auto *fd = cast<FuncDecl>(d);
586+
if (!fd->hasBody())
587+
return false;
585588

586-
if (auto *func = dyn_cast<FuncDecl>(d))
587-
if (func->hasForcedStaticDispatch())
589+
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()))
588590
return true;
589591

590-
if (auto *sf = dyn_cast<SourceFile>(dc))
591-
if (M.isWholeModule() || M.getAssociatedContext() == dc)
592-
return false;
592+
if (fd->hasForcedStaticDispatch())
593+
return true;
594+
595+
break;
596+
}
597+
case SILDeclRef::Kind::Allocator: {
598+
auto *cd = cast<ConstructorDecl>(d);
599+
// For factories, we don't need to emit a special thunk; the normal
600+
// foreign-to-native thunk is sufficient.
601+
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()) &&
602+
!cd->isFactoryInit() &&
603+
(dc->getSelfClassDecl() ||
604+
cd->hasBody()))
605+
return true;
606+
607+
break;
608+
}
609+
default:
610+
break;
611+
}
593612

594613
return false;
595614
}
@@ -618,18 +637,10 @@ SILFunction *SILGenModule::getFunction(SILDeclRef constant,
618637

619638
emittedFunctions[constant] = F;
620639

621-
if (isEmittedOnDemand(M, constant) &&
622-
!delayedFunctions.count(constant)) {
623-
auto *d = constant.getDecl();
624-
if (auto *func = dyn_cast<FuncDecl>(d)) {
625-
if (constant.kind == SILDeclRef::Kind::Func)
626-
emitFunction(func);
627-
} else if (auto *ctor = dyn_cast<ConstructorDecl>(d)) {
628-
// For factories, we don't need to emit a special thunk; the normal
629-
// foreign-to-native thunk is sufficient.
630-
if (!ctor->isFactoryInit() &&
631-
constant.kind == SILDeclRef::Kind::Allocator)
632-
emitConstructor(ctor);
640+
if (!delayedFunctions.count(constant)) {
641+
if (isEmittedOnDemand(M, constant)) {
642+
forcedFunctions.push_back(constant);
643+
return F;
633644
}
634645
}
635646

@@ -832,23 +843,18 @@ static void emitDelayedFunction(SILGenModule &SGM,
832843
static void emitOrDelayFunction(SILGenModule &SGM,
833844
SILDeclRef constant,
834845
bool forceEmission = false) {
846+
assert(!constant.isThunk());
847+
assert(!constant.isClangImported());
848+
835849
auto emitAfter = SGM.lastEmittedFunction;
836850

837851
SILFunction *f = nullptr;
838852

839-
// If the function is explicit or may be externally referenced, or if we're
840-
// forcing emission, we must emit it.
841-
bool mayDelay;
842-
// Shared thunks and Clang-imported definitions can always be delayed.
843-
if (constant.isThunk() || constant.isClangImported()) {
844-
mayDelay = !forceEmission;
845853
// Implicit decls may be delayed if they can't be used externally.
846-
} else {
847-
auto linkage = constant.getLinkage(ForDefinition);
848-
mayDelay = !forceEmission &&
849-
(constant.isImplicit() &&
850-
!isPossiblyUsedExternally(linkage, SGM.M.isWholeModule()));
851-
}
854+
auto linkage = constant.getLinkage(ForDefinition);
855+
bool mayDelay = !forceEmission &&
856+
(constant.isImplicit() &&
857+
!isPossiblyUsedExternally(linkage, SGM.M.isWholeModule()));
852858

853859
// Avoid emitting a delayable definition if it hasn't already been referenced.
854860
if (mayDelay)

test/ClangImporter/attr-swift_private.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,6 @@ public func testInitializers() {
5353
_ = Bar(__: 1)
5454
}
5555

56-
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC8__noArgsABSgyt_tcfcTO"
57-
// CHECK: @"\01L_selector(initWithNoArgs)"
58-
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC8__oneArgABSgs5Int32V_tcfcTO"
59-
// CHECK: @"\01L_selector(initWithOneArg:)"
60-
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC9__twoArgs5otherABSgs5Int32V_AGtcfcTO"
61-
// CHECK: @"\01L_selector(initWithTwoArgs:other:)"
62-
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC2__ABSgs5Int32V_tcfcTO"
63-
// CHECK: @"\01L_selector(init:)"
64-
6556
// CHECK-LABEL: define{{( protected)?}} swiftcc void @{{.+}}18testFactoryMethods
6657
public func testFactoryMethods() {
6758
// CHECK: @"\01L_selector(fooWithOneArg:)"
@@ -135,3 +126,12 @@ func testRawNames() {
135126
let _ = Foo.__foo // expected-error{{'__foo' has been replaced by 'init(__:)'}}
136127
}
137128
#endif
129+
130+
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC8__noArgsABSgyt_tcfcTO"
131+
// CHECK: @"\01L_selector(initWithNoArgs)"
132+
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC8__oneArgABSgs5Int32V_tcfcTO"
133+
// CHECK: @"\01L_selector(initWithOneArg:)"
134+
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC9__twoArgs5otherABSgs5Int32V_AGtcfcTO"
135+
// CHECK: @"\01L_selector(initWithTwoArgs:other:)"
136+
// CHECK-LABEL: define linkonce_odr hidden {{.+}} @"$sSo3BarC2__ABSgs5Int32V_tcfcTO"
137+
// CHECK: @"\01L_selector(init:)"

test/ClangImporter/objc_ir.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ func initCallToAllocInit(i i: CInt) {
5050
// CHECK-LABEL: linkonce_odr hidden {{.*}} @"$sSo1BC3intABSgs5Int32V_tcfC"
5151
// CHECK: call [[OPAQUE:%.*]]* @objc_allocWithZone
5252

53-
// CHECK: linkonce_odr hidden {{.*}} @"$sSo1BC3intABSgs5Int32V_tcfcTO"
54-
// CHECK: load i8*, i8** @"\01L_selector(initWithInt:)"
55-
// CHECK: call [[OPAQUE:%.*]]* bitcast (void ()* @objc_msgSend
56-
5753
// Indexed subscripting
5854
// CHECK-LABEL: define hidden swiftcc void @"$s7objc_ir19indexedSubscripting1b3idx1aySo1BC_SiSo1ACtF"
5955
func indexedSubscripting(b b: B, idx: Int, a: A) {
@@ -357,6 +353,10 @@ func testBlocksWithGenerics(hba: HasBlockArray) -> Any {
357353
}
358354

359355

356+
// CHECK-LABEL: linkonce_odr hidden {{.*}} @"$sSo1BC3intABSgs5Int32V_tcfcTO"
357+
// CHECK: load i8*, i8** @"\01L_selector(initWithInt:)"
358+
// CHECK: call [[OPAQUE:%.*]]* bitcast (void ()* @objc_msgSend
359+
360360
// CHECK: attributes [[NOUNWIND]] = { nounwind }
361361

362362
// CHECK: ![[SWIFT_NAME_ALIAS_VAR]] = !DILocalVariable(name: "obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]])

test/SILGen/objc_currying.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,6 @@ func curry_initializer() -> (Int) -> Gizmo? {
193193

194194
// CHECK-LABEL: sil shared [serializable] [ossa] @$sSo5GizmoC7bellsOnABSgSi_tcfC : $@convention(method) (Int, @thick Gizmo.Type) -> @owned Optional<Gizmo> {
195195

196-
// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo5GizmoC7bellsOnABSgSi_tcfcTO : $@convention(method) (Int, @owned Gizmo) -> @owned Optional<Gizmo> {
197-
198196
// CHECK-LABEL: sil private [ossa] @$s13objc_currying17curry_initializerSo5GizmoCSgSicyFAESicfu_ : $@convention(thin) (Int) -> @owned Optional<Gizmo> {
197+
198+
// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo5GizmoC7bellsOnABSgSi_tcfcTO : $@convention(method) (Int, @owned Gizmo) -> @owned Optional<Gizmo> {

test/SILGen/objc_imported_generic.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ public func arraysOfGenericParam<T: AnyObject>(y: Array<T>) {
9797
x.propertyArrayOfThings = y
9898
}
9999

100-
// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo12GenericClassC13arrayOfThingsAByxGSgSayxG_tcfcTO
101-
// CHECK: objc_method {{%.*}} : $GenericClass<T>, #GenericClass.init!initializer.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (NSArray, @owned GenericClass<τ_0_0>) -> @owned Optional<GenericClass<τ_0_0>>
102-
103100
// CHECK-LABEL: sil private [ossa] @$s21objc_imported_generic0C4FuncyyxmRlzClFyycfU_ : $@convention(thin) <V where V : AnyObject> () -> () {
104101
// CHECK: [[META:%.*]] = metatype $@thick GenericClass<V>.Type
105102
// CHECK: [[INIT:%.*]] = function_ref @$sSo12GenericClassCAByxGycfC : $@convention(method) <τ_0_0 where τ_0_0 : AnyObject> (@thick GenericClass<τ_0_0>.Type) -> @owned GenericClass<τ_0_0>
@@ -118,6 +115,9 @@ func configureWithoutOptions() {
118115
_ = GenericClass<NSObject>(options: nil)
119116
}
120117

118+
// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo12GenericClassC13arrayOfThingsAByxGSgSayxG_tcfcTO
119+
// CHECK: objc_method {{%.*}} : $GenericClass<T>, #GenericClass.init!initializer.foreign {{.*}}, $@convention(objc_method) @pseudogeneric <τ_0_0 where τ_0_0 : AnyObject> (NSArray, @owned GenericClass<τ_0_0>) -> @owned Optional<GenericClass<τ_0_0>>
120+
121121
// foreign to native thunk for init(options:), uses GenericOption : Hashable
122122
// conformance
123123

0 commit comments

Comments
 (0)