File: Link.cpp

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (202 lines) | stat: -rw-r--r-- 7,151 bytes parent folder | download
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);
}