1414#include " swift/SILOptimizer/PassManager/Transforms.h"
1515#include " swift/SIL/SILModule.h"
1616#include " swift/Serialization/SerializedSILLoader.h"
17+ #include " swift/Serialization/SerializedModuleLoader.h"
1718
1819using namespace swift ;
1920
2021static llvm::cl::opt<bool > LinkEmbeddedRuntime (" link-embedded-runtime" ,
2122 llvm::cl::init (true ));
2223
24+ static llvm::cl::opt<bool > LinkUsedFunctions (" link-used-functions" ,
25+ llvm::cl::init (true ));
26+
2327// ===----------------------------------------------------------------------===//
2428// Top Level Driver
2529// ===----------------------------------------------------------------------===//
@@ -45,6 +49,12 @@ class SILLinker : public SILModuleTransform {
4549 if (M.getOptions ().EmbeddedSwift && LinkEmbeddedRuntime) {
4650 linkEmbeddedRuntimeFromStdlib ();
4751 }
52+
53+ // In embedded Swift, we need to explicitly link any @_used globals and
54+ // functions from imported modules.
55+ if (M.getOptions ().EmbeddedSwift && LinkUsedFunctions) {
56+ linkUsedGlobalsAndFunctions ();
57+ }
4858 }
4959
5060 void linkEmbeddedRuntimeFromStdlib () {
@@ -82,23 +92,103 @@ class SILLinker : public SILModuleTransform {
8292 // Don't link allocating runtime functions in -no-allocations mode.
8393 if (M.getOptions ().NoAllocations && allocating) return ;
8494
85- // Bail if runtime function is already loaded.
86- if (M.lookUpFunction (name)) return ;
95+ // Swift Runtime functions are all expected to be SILLinkage::PublicExternal
96+ linkUsedFunctionByName (name, SILLinkage::PublicExternal);
97+ }
98+
99+ SILFunction *linkUsedFunctionByName (StringRef name,
100+ std::optional<SILLinkage> Linkage) {
101+ SILModule &M = *getModule ();
87102
88- SILFunction *Fn =
89- M.getSILLoader ()->lookupSILFunction (name, SILLinkage::PublicExternal);
90- if (!Fn) return ;
103+ // Bail if function is already loaded.
104+ if (auto *Fn = M.lookUpFunction (name)) return Fn;
105+
106+ SILFunction *Fn = M.getSILLoader ()->lookupSILFunction (name, Linkage);
107+ if (!Fn) return nullptr ;
91108
92109 if (M.linkFunction (Fn, LinkMode))
93110 invalidateAnalysis (Fn, SILAnalysis::InvalidationKind::Everything);
94111
95- // Make sure that dead-function-elimination doesn't remove runtime functions.
112+ // Make sure that dead-function-elimination doesn't remove the explicitly
113+ // linked functions.
114+ //
96115 // TODO: lazily emit runtime functions in IRGen so that we don't have to
97116 // rely on dead-stripping in the linker to remove unused runtime
98117 // functions.
99118 if (Fn->isDefinition ())
100119 Fn->setLinkage (SILLinkage::Public);
120+
121+ return Fn;
122+ }
123+
124+ SILGlobalVariable *linkUsedGlobalVariableByName (StringRef name) {
125+ SILModule &M = *getModule ();
126+
127+ // Bail if runtime function is already loaded.
128+ if (auto *GV = M.lookUpGlobalVariable (name)) return GV;
129+
130+ SILGlobalVariable *GV = M.getSILLoader ()->lookupSILGlobalVariable (name);
131+ if (!GV) return nullptr ;
132+
133+ // Make sure that dead-function-elimination doesn't remove the explicitly
134+ // linked global variable.
135+ if (GV->isDefinition ())
136+ GV->setLinkage (SILLinkage::Public);
137+
138+ return GV;
101139 }
140+
141+ void linkUsedGlobalsAndFunctions () {
142+ SmallVector<VarDecl *, 32 > Globals;
143+ SmallVector<AbstractFunctionDecl *, 32 > Functions;
144+ collectUsedDeclsFromLoadedModules (Globals, Functions);
145+
146+ for (auto *G : Globals) {
147+ auto declRef = SILDeclRef (G, SILDeclRef::Kind::Func);
148+ linkUsedGlobalVariableByName (declRef.mangle ());
149+ }
150+
151+ for (auto *F : Functions) {
152+ auto declRef = SILDeclRef (F, SILDeclRef::Kind::Func);
153+ auto *Fn = linkUsedFunctionByName (declRef.mangle (), /* Linkage*/ {});
154+
155+ // If we have @_cdecl or @_silgen_name, also link the foreign thunk
156+ if (Fn->hasCReferences ()) {
157+ auto declRef = SILDeclRef (F, SILDeclRef::Kind::Func, /* isForeign*/ true );
158+ linkUsedFunctionByName (declRef.mangle (), /* Linkage*/ {});
159+ }
160+ }
161+ }
162+
163+ void collectUsedDeclsFromLoadedModules (
164+ SmallVectorImpl<VarDecl *> &Globals,
165+ SmallVectorImpl<AbstractFunctionDecl *> &Functions) {
166+ SILModule &M = *getModule ();
167+
168+ for (const auto &Entry : M.getASTContext ().getLoadedModules ()) {
169+ for (auto File : Entry.second ->getFiles ()) {
170+ if (auto LoadedAST = dyn_cast<SerializedASTFile>(File)) {
171+ auto matcher = [](const DeclAttributes &attrs) -> bool {
172+ return attrs.hasAttribute <UsedAttr>();
173+ };
174+
175+ SmallVector<Decl *, 32 > Decls;
176+ LoadedAST->getTopLevelDeclsWhereAttributesMatch (Decls, matcher);
177+
178+ for (Decl *D : Decls) {
179+ if (AbstractFunctionDecl *F = dyn_cast<AbstractFunctionDecl>(D)) {
180+ Functions.push_back (F);
181+ } else if (VarDecl *G = dyn_cast<VarDecl>(D)) {
182+ Globals.push_back (G);
183+ } else {
184+ assert (false && " only funcs and globals can be @_used" );
185+ }
186+ }
187+ }
188+ }
189+ }
190+ }
191+
102192};
103193} // end anonymous namespace
104194
0 commit comments