Skip to content

Commit cd7924a

Browse files
authored
Merge pull request #84682 from DougGregor/embedded-deferred-code-gen-external-symbols
2 parents 9fa9ea7 + cc519a0 commit cd7924a

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)