Skip to content

Commit cc519a0

Browse files
committed
[Embedded] Identify more places to emit symbols even with deferred code generation
Deferred code generation only produces symbols when they are needed. Expand this out to cover more of the cases where we need them: * @c/@_cdecl with and without @implementation * @_expose(Cxx) and @_expose(Wasm) * @_section and @_used * (already present) the main entry point Part of the Embedded Swift linkage model. Also fixes #74328 / rdar://147207945 along the way.
1 parent 67c7fbc commit cc519a0

File tree

8 files changed

+169
-0
lines changed

8 files changed

+169
-0
lines changed

include/swift/SIL/SILDeclRef.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ struct SILDeclRef {
415415
/// embedded linkage model.
416416
bool hasNonUniqueDefinition() const;
417417

418+
/// True if the declaration is explicitly marked as being exposed to a
419+
/// foreign language or environment,
420+
static bool declExposedToForeignLanguage(const ValueDecl *decl);
421+
418422
/// True if the declaration should have a non-unique definition based on the
419423
/// embedded linkage model.
420424
static bool declHasNonUniqueDefinition(const ValueDecl *decl);

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,29 @@ bool SILDeclRef::hasNonUniqueDefinition() const {
11531153
return false;
11541154
}
11551155

1156+
bool SILDeclRef::declExposedToForeignLanguage(const ValueDecl *decl) {
1157+
// @c / @_cdecl / @objc.
1158+
if (decl->getAttrs().hasAttribute<CDeclAttr>() ||
1159+
(decl->getAttrs().hasAttribute<ObjCAttr>() &&
1160+
decl->getDeclContext()->isModuleScopeContext())) {
1161+
return true;
1162+
}
1163+
1164+
// @_expose that isn't negated.
1165+
for (auto *expose : decl->getAttrs().getAttributes<ExposeAttr>()) {
1166+
switch (expose->getExposureKind()) {
1167+
case ExposureKind::Cxx:
1168+
case ExposureKind::Wasm:
1169+
return true;
1170+
1171+
case ExposureKind::NotCxx:
1172+
continue;
1173+
}
1174+
}
1175+
1176+
return false;
1177+
}
1178+
11561179
bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) {
11571180
// This function only forces the issue in embedded.
11581181
if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded))
@@ -1167,6 +1190,28 @@ bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) {
11671190
if (decl->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
11681191
return true;
11691192

1193+
// If the declaration is marked in a manner that indicates that other
1194+
// systems will expect it to have a symbol, then it has a unique definition.
1195+
// There are a few cases here.
1196+
1197+
// - @implementation explicitly says that we are implementing something to
1198+
// be called from another language, so call it non-unique.
1199+
if (decl->isObjCImplementation())
1200+
return false;
1201+
1202+
// - @c / @_cdecl / @objc / @_expose expect to be called from another
1203+
// language if the symbol itself would be visible.
1204+
if (declExposedToForeignLanguage(decl) &&
1205+
decl->getFormalAccess() >= AccessLevel::Internal) {
1206+
return false;
1207+
}
1208+
1209+
// - @_section and @_used imply that external tools will look for this symbol.
1210+
if (decl->getAttrs().hasAttribute<SectionAttr>() ||
1211+
decl->getAttrs().hasAttribute<UsedAttr>()) {
1212+
return false;
1213+
}
1214+
11701215
auto module = decl->getModuleContext();
11711216
auto &ctx = module->getASTContext();
11721217

lib/SIL/IR/SILFunction.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,18 @@ SILFunction::isPossiblyUsedExternally() const {
10691069
if (markedAsUsed())
10701070
return true;
10711071

1072+
// If this function is exposed to a foreign language, it can be used
1073+
// externally (by that language).
1074+
if (auto decl = getDeclRef().getDecl()) {
1075+
if (SILDeclRef::declExposedToForeignLanguage(decl))
1076+
return true;
1077+
}
1078+
1079+
// If this function was explicitly placed in a section or given a WebAssembly
1080+
// export, it can be used externally.
1081+
if (!Section.empty() || !WasmExportName.empty())
1082+
return true;
1083+
10721084
if (shouldBePreservedForDebugger())
10731085
return true;
10741086

lib/SIL/IR/SILGlobalVariable.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const {
9191
if (markedAsUsed())
9292
return true;
9393

94+
if (getSectionAttr())
95+
return true;
96+
9497
SILLinkage linkage = getLinkage();
9598
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
9699
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
double clib_func1(void);
2+
double clib_func2(void);
3+
double clib_func3(void);
4+
double clib_func4(void);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
module CDependency {
22
header "CHeader.h"
33
}
4+
5+
module MyModuleExports {
6+
header "MyModuleExports.h"
7+
}

test/embedded/linkage/c.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Check that C functions are exported as needed.
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: executable_test
5+
// REQUIRES: swift_feature_Embedded
6+
// REQUIRES: swift_feature_DeferredCodeGen
7+
// REQUIRES: swift_feature_CDecl
8+
// REQUIRES: swift_feature_CImplementation
9+
// REQUIRES: swift_feature_SymbolLinkageMarkers
10+
11+
// RUN: %target-swift-frontend -emit-ir -o - %s -I %S/Inputs -package-name MyPackage -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -enable-experimental-feature CDecl -enable-experimental-feature CImplementation -enable-experimental-feature SymbolLinkageMarkers -parse-as-library | %FileCheck %s
12+
13+
import MyModuleExports
14+
15+
// ---------------------------------------------------------------------------
16+
// @c / @_cdecl on > internal declarations cause symbol emission
17+
// ---------------------------------------------------------------------------
18+
19+
// CHECK: define {{(protected |dllexport )?}}void @lib_publicCDeclFunc()
20+
@_cdecl("lib_publicCDeclFunc")
21+
public func f1() { }
22+
23+
// CHECK: define {{(protected |dllexport )?}}void @lib_publicCFunc()
24+
@c(lib_publicCFunc)
25+
package func f2() { }
26+
27+
// CHECK: define hidden void @lib_publicCDeclFunc3
28+
@_cdecl("lib_publicCDeclFunc3")
29+
internal func f3() { }
30+
31+
// CHECK: define hidden void @lib_publicCDeclFunc4
32+
@c("lib_publicCDeclFunc4")
33+
internal func f4() { }
34+
35+
// CHECK-NOT: lib_publicCDeclFunc5
36+
@_cdecl("lib_publicCDeclFunc5")
37+
private func f5() { }
38+
39+
// CHECK-NOT: lib_publicCDeclFunc6
40+
@c("lib_publicCDeclFunc6")
41+
private func f6() { }
42+
43+
// ---------------------------------------------------------------------------
44+
// @implementation @c / @_cdecl cause symbol emission
45+
// ---------------------------------------------------------------------------
46+
47+
// CHECK: define {{(protected |dllexport )?}}double @clib_func1
48+
@_cdecl("clib_func1") @implementation
49+
public func clib_func1() -> Double { 0 }
50+
51+
// CHECK: define {{(protected |dllexport )?}}double @clib_func2
52+
@c @implementation
53+
package func clib_func2() -> Double { 0 }
54+
55+
// CHECK: define hidden double @clib_func3
56+
@_cdecl("clib_func3") @implementation
57+
internal func clib_func3() -> Double { 0 }
58+
59+
// CHECK: define hidden double @clib_func4
60+
@c @implementation
61+
internal func clib_func4() -> Double { 0 }
62+
63+
// ---------------------------------------------------------------------------
64+
// @_section causes symbol emission
65+
// ---------------------------------------------------------------------------
66+
67+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$e1c15symbolInSectionyyF"
68+
@_section("__TEXT,__mysection")
69+
public func symbolInSection() { }
70+
71+
// CHECK: define hidden swiftcc void @"$e1c23internalSymbolInSectionyyF"
72+
@_section("__TEXT,__mysection")
73+
func internalSymbolInSection() { }
74+
75+
// ---------------------------------------------------------------------------
76+
// @_used causes symbol emission
77+
// ---------------------------------------------------------------------------
78+
79+
// CHECK: define hidden swiftcc void @"$e1c10usedSymbolyyF"
80+
@_used
81+
func usedSymbol() { }

test/embedded/linkage/cxx.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Check that C++ functions are exported as needed.
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: executable_test
5+
// REQUIRES: swift_feature_Embedded
6+
// REQUIRES: swift_feature_DeferredCodeGen
7+
8+
// RUN: %target-swift-frontend -emit-ir -o - %s -I %S/Inputs -package-name MyPackage -enable-experimental-feature Embedded -enable-experimental-feature DeferredCodeGen -parse-as-library -cxx-interoperability-mode=default | %FileCheck %s
9+
10+
// CHECK: define hidden swiftcc void @"$e3cxx2f1yyF"()
11+
@_expose(Cxx)
12+
func f1() { }
13+
14+
// CHECK-NOT: 2f2
15+
@_expose(!Cxx)
16+
public func f2() { }

0 commit comments

Comments
 (0)