1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
//===--- Link.cpp - Link in transparent SILFunctions from module ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SIL/SILModule.h"
#include "swift/Serialization/SerializedSILLoader.h"
#include "swift/Serialization/SerializedModuleLoader.h"
using namespace swift;
static llvm::cl::opt<bool> LinkEmbeddedRuntime("link-embedded-runtime",
llvm::cl::init(true));
static llvm::cl::opt<bool> LinkUsedFunctions("link-used-functions",
llvm::cl::init(true));
//===----------------------------------------------------------------------===//
// Top Level Driver
//===----------------------------------------------------------------------===//
namespace {
/// Copies code from the standard library into the user program to enable
/// optimizations.
class SILLinker : public SILModuleTransform {
SILModule::LinkingMode LinkMode;
public:
explicit SILLinker(SILModule::LinkingMode LinkMode) : LinkMode(LinkMode) {}
void run() override {
SILModule &M = *getModule();
for (auto &Fn : M)
if (M.linkFunction(&Fn, LinkMode))
invalidateAnalysis(&Fn, SILAnalysis::InvalidationKind::Everything);
// In embedded Swift, the stdlib contains all the runtime functions needed
// (swift_retain, etc.). Link them in so they can be referenced in IRGen.
if (M.getOptions().EmbeddedSwift && LinkEmbeddedRuntime) {
linkEmbeddedRuntimeFromStdlib();
}
// In embedded Swift, we need to explicitly link any @_used globals and
// functions from imported modules.
if (M.getOptions().EmbeddedSwift && LinkUsedFunctions) {
linkUsedGlobalsAndFunctions();
}
}
void linkEmbeddedRuntimeFromStdlib() {
using namespace RuntimeConstants;
#define FUNCTION(ID, MODULE, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS, \
EFFECT, MEMORY_EFFECTS) \
linkEmbeddedRuntimeFunctionByName(#NAME, EFFECT); \
if (getModule()->getASTContext().hadError()) \
return;
#define RETURNS(...)
#define ARGS(...)
#define NO_ARGS
#define ATTRS(...)
#define NO_ATTRS
#define EFFECT(...) { __VA_ARGS__ }
#define MEMORY_EFFECTS(...)
#define UNKNOWN_MEMEFFECTS
#include "swift/Runtime/RuntimeFunctions.def"
// swift_retainCount is not part of private contract between the compiler and runtime, but we still need to link it
linkEmbeddedRuntimeFunctionByName("swift_retainCount", { RefCounting });
}
void linkEmbeddedRuntimeFunctionByName(StringRef name,
ArrayRef<RuntimeEffect> effects) {
SILModule &M = *getModule();
bool allocating = false;
for (RuntimeEffect rt : effects)
if (rt == RuntimeEffect::Allocating || rt == RuntimeEffect::Deallocating)
allocating = true;
// Don't link allocating runtime functions in -no-allocations mode.
if (M.getOptions().NoAllocations && allocating) return;
// Swift Runtime functions are all expected to be SILLinkage::PublicExternal
linkUsedFunctionByName(name, SILLinkage::PublicExternal);
}
SILFunction *linkUsedFunctionByName(StringRef name,
std::optional<SILLinkage> Linkage) {
SILModule &M = *getModule();
// Bail if function is already loaded.
if (auto *Fn = M.lookUpFunction(name)) return Fn;
SILFunction *Fn = M.getSILLoader()->lookupSILFunction(name, Linkage);
if (!Fn) return nullptr;
if (M.linkFunction(Fn, LinkMode))
invalidateAnalysis(Fn, SILAnalysis::InvalidationKind::Everything);
// Make sure that dead-function-elimination doesn't remove the explicitly
// linked functions.
//
// TODO: lazily emit runtime functions in IRGen so that we don't have to
// rely on dead-stripping in the linker to remove unused runtime
// functions.
if (Fn->isDefinition())
Fn->setLinkage(SILLinkage::Public);
return Fn;
}
SILGlobalVariable *linkUsedGlobalVariableByName(StringRef name) {
SILModule &M = *getModule();
// Bail if runtime function is already loaded.
if (auto *GV = M.lookUpGlobalVariable(name)) return GV;
SILGlobalVariable *GV = M.getSILLoader()->lookupSILGlobalVariable(name);
if (!GV) return nullptr;
// Make sure that dead-function-elimination doesn't remove the explicitly
// linked global variable.
if (GV->isDefinition())
GV->setLinkage(SILLinkage::Public);
return GV;
}
void linkUsedGlobalsAndFunctions() {
SmallVector<VarDecl *, 32> Globals;
SmallVector<AbstractFunctionDecl *, 32> Functions;
collectUsedDeclsFromLoadedModules(Globals, Functions);
for (auto *G : Globals) {
auto declRef = SILDeclRef(G, SILDeclRef::Kind::Func);
linkUsedGlobalVariableByName(declRef.mangle());
}
for (auto *F : Functions) {
auto declRef = SILDeclRef(F, SILDeclRef::Kind::Func);
auto *Fn = linkUsedFunctionByName(declRef.mangle(), /*Linkage*/{});
// If we have @_cdecl or @_silgen_name, also link the foreign thunk
if (Fn->hasCReferences()) {
auto declRef = SILDeclRef(F, SILDeclRef::Kind::Func, /*isForeign*/true);
linkUsedFunctionByName(declRef.mangle(), /*Linkage*/{});
}
}
}
void collectUsedDeclsFromLoadedModules(
SmallVectorImpl<VarDecl *> &Globals,
SmallVectorImpl<AbstractFunctionDecl *> &Functions) {
SILModule &M = *getModule();
for (const auto &Entry : M.getASTContext().getLoadedModules()) {
for (auto File : Entry.second->getFiles()) {
if (auto LoadedAST = dyn_cast<SerializedASTFile>(File)) {
auto matcher = [](const DeclAttributes &attrs) -> bool {
return attrs.hasAttribute<UsedAttr>();
};
SmallVector<Decl *, 32> Decls;
LoadedAST->getTopLevelDeclsWhereAttributesMatch(Decls, matcher);
for (Decl *D : Decls) {
if (AbstractFunctionDecl *F = dyn_cast<AbstractFunctionDecl>(D)) {
Functions.push_back(F);
} else if (VarDecl *G = dyn_cast<VarDecl>(D)) {
Globals.push_back(G);
} else {
assert(false && "only funcs and globals can be @_used");
}
}
}
}
}
}
};
} // end anonymous namespace
SILTransform *swift::createMandatorySILLinker() {
return new SILLinker(SILModule::LinkingMode::LinkNormal);
}
SILTransform *swift::createPerformanceSILLinker() {
return new SILLinker(SILModule::LinkingMode::LinkAll);
}
|